package edu.thu.studio.ormdesigner.model.diagram.node;

import java.util.ArrayList;
import java.util.List;

import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
import com.thoughtworks.xstream.annotations.XStreamOmitField;

import edu.thu.studio.ormdesigner.model.AbstractObjectModel;
import edu.thu.studio.ormdesigner.model.diagram.Diagram;
import edu.thu.studio.ormdesigner.model.diagram.link.Link;
import edu.thu.studio.ormdesigner.model.orm.table.ColumnSet;
import edu.thu.studio.ormdesigner.model.orm.table.Table;
import edu.thu.studio.ormdesigner.util.Utils;

public abstract class Node extends AbstractObjectModel {
    
    private static final long serialVersionUID = -5143984125818569247L;
    
    public static final int DEFAULT_WIDTH = 160;
    
    public static final int DEFAULT_HEIGHT = 220;
    
    @XStreamOmitField()
    protected List<Link> incomings = new ArrayList<Link>();
    
    @XStreamOmitField()
    protected List<Link> outgoings = new ArrayList<Link>();
    
    @XStreamAsAttribute
    private String type;
    
    @XStreamAsAttribute
    private String style;
    
    @XStreamAsAttribute
    private Boolean visible = true;
    
    @XStreamAsAttribute
    protected Boolean original = true;
    
    @XStreamAsAttribute
    @XStreamAlias("z-index")
    private Integer zIndex;
    
    @XStreamAsAttribute
    @XStreamAlias("ref-id")
    private String refId;
    
    @XStreamAsAttribute
    public int x;
    
    @XStreamAsAttribute
    public int y;
    
    @XStreamAsAttribute
    public int width;
    
    @XStreamAsAttribute
    public int height;
    
    public Node() {
        super();
    }
    
    public Boolean isOriginal() {
        return original;
    }
    
    public void setOriginal(Boolean original) {
        this.original = original;
    }
    
    public String getRefId() {
        return refId;
    }
    
    public void setRefId(String refId) {
        this.refId = refId;
    }
    
    public String getType() {
        return type;
    }
    
    public void setType(String type) {
        this.type = type;
    }
    
    public String getStyle() {
        return style;
    }
    
    public void setStyle(String style) {
        this.style = style;
    }
    
    public Boolean getVisible() {
        return visible;
    }
    
    public void setVisible(Boolean visible) {
        this.visible = visible;
    }
    
    public Integer getzIndex() {
        return zIndex;
    }
    
    public void setzIndex(Integer zIndex) {
        this.zIndex = zIndex;
    }
    
    public int getX() {
        return this.x;
    }
    
    public int getY() {
        return this.y;
    }
    
    public int getWidth() {
        return this.width;
    }
    
    public int getHeight() {
        return this.height;
    }
    
    public void setX(int x) {
        this.x = x;
    }
    
    public void setY(int y) {
        this.y = y;
    }
    
    public void setWidth(int width) {
        this.width = width;
    }
    
    public void setHeight(int height) {
        this.height = height;
    }
    
    public void setXY(int x, int y) {
        this.x = x;
        this.y = y;
    }
    
    public void setRectangle(int x, int y, int width, int height) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
    }
    
    public List<Link> getIncomings() {
        return incomings;
    }
    
    public List<Link> getOutgoings() {
        return outgoings;
    }
    
    public void setIncoming(List<Link> relations) {
        this.incomings = relations;
    }
    
    public void setOutgoing(List<Link> relations) {
        this.outgoings = relations;
    }
    
    public void addIncoming(Link relation) {
        this.incomings.add(relation);
    }
    
    public void removeIncoming(Link relation) {
        this.incomings.remove(relation);
    }
    
    public void addOutgoing(Link relation) {
        this.outgoings.add(relation);
    }
    
    public void removeOutgoing(Link relation) {
        this.outgoings.remove(relation);
    }
    
    public List<Node> getReferringElementList() {
        List<Node> referringElementList = new ArrayList<Node>();
        
        for (Link connectionElement : this.getOutgoings()) {
            Node targetElement = connectionElement.getTarget();
            
            referringElementList.add(targetElement);
        }
        
        return referringElementList;
    }
    
    public List<Node> getReferedElementList() {
        List<Node> referedElementList = new ArrayList<Node>();
        
        for (Link connectionElement : this.getIncomings()) {
            Node sourceElement = connectionElement.getSource();
            
            referedElementList.add(sourceElement);
        }
        
        return referedElementList;
    }
    
    public void refreshSourceConnections() {
        if (isUpdateable()) {
            this.firePropertyChange("refreshSourceConnections", null, null);
        }
    }
    
    public void refreshTargetConnections() {
        if (isUpdateable()) {
            this.firePropertyChange("refreshTargetConnections", null, null);
        }
    }
    
    /**
     * {@inheritDoc}
     */
    @Override
    public Node clone() {
        Node clone = (Node) super.clone();
        clone.setIncoming(new ArrayList<Link>());
        clone.setOutgoing(new ArrayList<Link>());
        return clone;
    }
    
    public ColumnSet getColumns() {
        return getRefTable().getColumns();
    }
    
    public String getName() {
        return (original ? "" : "[快照]-") + getRefTable().getName();
    }
    
    public String getCode() {
        return getRefTable().getCode();
    }
    
    @XStreamOmitField()
    protected Diagram diagram;
    
    public Diagram getDiagram() {
        return diagram;
    }
    
    public void setDiagram(Diagram diagram) {
        this.diagram = diagram;
    }
    
    @XStreamOmitField()
    private Table refTable;
    
    public Table getRefTable() {
        return refTable;
    }
    
    public void setRefTable(Table refTable) {
        this.refTable = refTable;
    }
    
    public void checkAndInit() {
        if (null == id) {
            id = Utils.getUUID();
        }
    }
    
}
